﻿
using System;
using System.Windows.Forms;
using TP_Link_HTTP_Lib;
using ClipboardMonitor;
using DialerConfig;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
using System.IO;

namespace DialerMainUi
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class MainForm : Form
	{
		[DllImport("User32.dll", EntryPoint = "FindWindow")]
		static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
		[DllImport("User32.dll", EntryPoint = "FindWindowEx")]
		static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
		[DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
		static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);
		[DllImport("User32.dll", EntryPoint = "ShowWindow")]
		static extern int ShowWindow(IntPtr hWnd, int showCmd);
		public const int WM_SETTEXT = 0x000C;
		public const int WM_CLICK = 0x00F5;
		public const int CB_SETCURSEL = 0x014E;
		private delegate void uidlg(int stat, string errInfo);
		Thread dialThrd;
		Process subAppPcs;
		DialerConfigLib cfg;
		public MainForm()
		{
			InitializeComponent();
			if (!Directory.Exists(Environment.GetEnvironmentVariable("APPDATA") + @"\CMCCTRouterDailer"))
				Directory.CreateDirectory(Environment.GetEnvironmentVariable("APPDATA") + @"\CMCCTRouterDailer");
			cfg = new DialerConfigLib(Environment.GetEnvironmentVariable("APPDATA") + @"\CMCCTRouterDailer\Config.ini");
		}
		void trdUpdateUI(int status, string errInfo = "")
		{
			if (InvokeRequired) {
				var ud = new uidlg(trdUpdateUI);
				Invoke(ud, new object[] { status, errInfo });
			} else {
				if (status < 0)
					labelStatusBar.Text = "遇到错误";
				switch (status) {
					case -1:
						MessageBox.Show("无法找到算号器！本软件可能不完整。\r\n" + errInfo, "Error");
						break;
					case -2:
						MessageBox.Show("无法连接到路由器地址，请检查网络连接！" + errInfo, "Error");
						break;
					case -3:
						MessageBox.Show("无法启动算号器！请检查计算机设置。\r\n" + errInfo, "Error");
						break;
					case -4:
						MessageBox.Show("获取到的剪切板数据不正确，请尝试关闭自动操作。\r\n" + errInfo, "Error");
						break;
					case -5:
						MessageBox.Show("无法操作目标程序，请尝试关闭自动操作。\r\n" + errInfo, "Error");
						break;
					case -6:
						MessageBox.Show("长时间没有获取到剪切板数据。" + errInfo, "Error");
						break;
					case 0:
						labelStatusBar.Text = "等待用户操作";
						break;
					case 1:
						labelStatusBar.Text = "正在监控系统剪切板";
						break;
					case 2:
						labelStatusBar.Text = "正在连接路由器拨号";
						break;
					case 3:
						labelStatusBar.Text = "拨号请求已经发出";
						break;
					case 4:
						labelStatusBar.Text = "正在启动算号器";
						break;
					case 5:
						labelStatusBar.Text = "初次剪切板数据不正确，正在重试。";
						break;
					default:
						MessageBox.Show("不明的错误：未接收到可识别的状态代码。\r\n" + errInfo, "Error");
						break;
				}
			}
		}
		void dailReady()
		{
			trdUpdateUI(1);
			subAppPcs = new Process();
			if (File.Exists("SubApp1.exe"))
				subAppPcs.StartInfo.FileName = "SubApp1.exe";
			else {
				try {
					File.Copy("SubApp1.bin", Environment.GetEnvironmentVariable("TEMP") + @"\CMCCTRouterDailer_Sub1.exe", true);
					subAppPcs.StartInfo.FileName = Environment.GetEnvironmentVariable("TEMP") + @"\CMCCTRouterDailer_Sub1.exe";
				} catch {
					trdUpdateUI(-1);
					return;
				}
			}
			try {
				subAppPcs.Start();
				if (cfg.autoSendAction)
					subAppPcs.WaitForInputIdle();
			} catch {
				trdUpdateUI(-1);
				return;
			}
			string ispUsername;
			if (cfg.autoSendAction) {
				bool noContinue = false;
				SubAppOperation:
				IntPtr windowPtr;
				int findWindowTimes = 0;
				do {
					if (findWindowTimes > 250) {
						trdUpdateUI(-5);
						return;
					}
					windowPtr = FindWindow("#32770", "");
					findWindowTimes += 1;
					Thread.Sleep(500);          //Thread.Sleep 一定要放在FindWindow后面，因为此时程序可能还没有完成界面绘制。
				} while (windowPtr.Equals(IntPtr.Zero));
				ShowWindow(windowPtr, 2);
				subAppPcs.WaitForInputIdle();
				IntPtr accountInputPtr = FindWindowEx(windowPtr, (IntPtr)0, "RichEdit20A", "");
				if (accountInputPtr.Equals(IntPtr.Zero)) {
					trdUpdateUI(-5);
					return;
				}
				SendMessage(accountInputPtr, WM_SETTEXT, IntPtr.Zero, cfg.ispUsername);
				subAppPcs.WaitForInputIdle();
				IntPtr passwordInputPtr = FindWindowEx(windowPtr, accountInputPtr, "RichEdit20A", "");
				if (passwordInputPtr.Equals(IntPtr.Zero)) {
					trdUpdateUI(-5);
					return;
				}
				SendMessage(passwordInputPtr, WM_SETTEXT, IntPtr.Zero, cfg.ispPassword);
				subAppPcs.WaitForInputIdle();
				IntPtr versionSelectCBPtr = FindWindowEx(windowPtr, IntPtr.Zero, "ComboBox", null);
				if (versionSelectCBPtr.Equals(IntPtr.Zero)) {
					trdUpdateUI(-5);
					return;
				}
				SendMessage(versionSelectCBPtr, CB_SETCURSEL, (IntPtr)8, null);
				subAppPcs.WaitForInputIdle();
				IntPtr calcButtonPtr = FindWindowEx(windowPtr, IntPtr.Zero, "Button", "C");
				if (calcButtonPtr.Equals(IntPtr.Zero)) {
					trdUpdateUI(-5);
					return;
				}
				SendMessage(calcButtonPtr, WM_CLICK, IntPtr.Zero, null);
				subAppPcs.WaitForInputIdle();
				Thread.Sleep(100);
				ispUsername = Clipboard.GetText();
				if (!ispUsername.StartsWith("~ghca", StringComparison.Ordinal)) {
					if (noContinue) {
						trdUpdateUI(-4);
						return;
					}
					trdUpdateUI(5);
					noContinue = true;
					subAppPcs.Kill();
					Thread.Sleep(500);
					subAppPcs.Start();
					subAppPcs.WaitForInputIdle();
					goto SubAppOperation;
				}
			} else {
				var cma = new ClicpboardMonitorAction();
				ispUsername = cma.getNewStringStartWith("~ghca", 60);
				if (!ispUsername.StartsWith("~ghca", StringComparison.Ordinal)) {
					trdUpdateUI(-6);
					return;
				}
			}
			string routerDomainIp = cfg.routerAddress;
			int routerPort = 80;
			int routerPortStringOffset;
			try {
				subAppPcs.CloseMainWindow();
			} catch (Exception e) {
				Console.WriteLine(e);
			}
			if (0 < (routerPortStringOffset = cfg.routerAddress.IndexOf(':'))) {
				Int32.TryParse(cfg.routerAddress.Substring(routerPortStringOffset + 1), out routerPort);
				routerDomainIp = cfg.routerAddress.Substring(0, routerPortStringOffset);
			}
			var tpRouter = new TPLinkHTTP(routerDomainIp, routerPort, cfg.routerAdminUsername, cfg.routerAdminPassword);
			trdUpdateUI(2);
			tpRouter.sendPPPoEConfig(ispUsername, cfg.ispPassword, (cfg.isAutoDisconnect ? cfg.autoDisconnectTime.ToString() : "0"));
			Thread.Sleep(500);
			tpRouter.reConnect();
			trdUpdateUI(3);
		}
		void updateConfig()
		{
			cfg.routerAddress = textBoxRouterAddress.Text;
			cfg.routerAdminUsername = textBoxRouterAdminAcc.Text;
			cfg.routerAdminPassword = textBoxRouterAdminPsw.Text;
			cfg.ispUsername = textBoxIspAcc.Text;
			cfg.ispPassword = textBoxIspPsw.Text;
			cfg.isAutoDisconnect = checkBoxAutoDisconnect.Checked;
			cfg.autoDisconnectTime = Convert.ToInt32(numericUpDownAutoDisconnectMinutes.Value);
			cfg.autoRunCalcTool = checkBoxAutoRunCalc.Checked;
			cfg.autoSendAction = checkBoxAutoUseCalc.Checked;
		}
		
		
		void ButtonExitProgramClick(object sender, EventArgs e)
		{
			Close();
		}
		
		void MainFormFormClosed(object sender, FormClosedEventArgs e)
		{
			try {
				dialThrd.Abort();
			} catch (Exception e2) {
				Console.WriteLine(e2);
			}
			if (checkBoxRememberSethings.Checked) {
				updateConfig();
				cfg.saveConfig();
			}
		}
		
		void MainFormLoad(object sender, EventArgs e)
		{
			cfg.readConfig();
			textBoxRouterAddress.Text = cfg.routerAddress;
			textBoxRouterAdminAcc.Text = cfg.routerAdminUsername;
			textBoxRouterAdminPsw.Text = cfg.routerAdminPassword;
			textBoxIspAcc.Text = cfg.ispUsername;
			textBoxIspPsw.Text = cfg.ispPassword;
			checkBoxAutoDisconnect.Checked = cfg.isAutoDisconnect;
			numericUpDownAutoDisconnectMinutes.Value = cfg.autoDisconnectTime;
			checkBoxAutoRunCalc.Checked = cfg.autoRunCalcTool;
			checkBoxAutoUseCalc.Checked = cfg.autoSendAction;
			CheckBoxAutoDisconnectCheckedChanged(sender, e);
			if (cfg.autoRunCalcTool)
				ButtonStartClick(sender, e);
		}

		void ButtonStartClick(object sender, EventArgs e)
		{
			updateConfig();
			try {
				dialThrd.Abort();
			} catch (Exception e2) {
				Console.WriteLine(e2);
			}
			dialThrd = new Thread(new ThreadStart(dailReady));
			dialThrd.SetApartmentState(ApartmentState.STA);
			dialThrd.Start();
		}
		
		void CheckBoxAutoDisconnectCheckedChanged(object sender, EventArgs e)
		{
			numericUpDownAutoDisconnectMinutes.Enabled = checkBoxAutoDisconnect.Checked;
		}
		
		void ButtonHelpClick(object sender, EventArgs e)
		{
			var subHelpForm = new HelpForm(this);
			Hide();
			subHelpForm.Show();
		}
	}
}
